package com.ybl.store.backend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ybl.store.backend.dao.entity.ClerkDO;
import com.ybl.store.backend.dao.entity.ManagerDO;
import com.ybl.store.backend.dao.mapper.ClerkMapper;
import com.ybl.store.backend.dao.mapper.ManagerMapper;
import com.ybl.store.backend.dto.UserInfoDTO;
import com.ybl.store.backend.dto.req.ClerkSaveReqDTO;
import com.ybl.store.backend.dto.req.ClerkUpdateReqDTO;
import com.ybl.store.backend.dto.resp.*;
import com.ybl.store.backend.dto.resp.ClerkSaveRespDTO;
import com.ybl.store.backend.dto.resp.ClerkPageRespDTO;
import com.ybl.store.backend.service.ClerkService;
import com.ybl.store.backend.service.UserService.UserService;
import com.ybl.store.common.constant.DelFlag;
import com.ybl.store.common.constant.UserIdentity;
import com.ybl.store.common.context.UserContext;
import com.ybl.store.common.convention.errorcode.BaseErrorCode;
import com.ybl.store.common.convention.exception.ClientException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
public class ClerkServiceImpl extends ServiceImpl<ClerkMapper, ClerkDO> implements ClerkService {

    private final ManagerMapper managerMapper;

    private final UserService userService;

    @Override
    public ClerkSaveRespDTO saveClerk(ClerkSaveReqDTO requestParam) {
        isAuthorized(requestParam.getManagerId());

        if (managerMapper.selectById(requestParam.getManagerId()) == null) {
            throw new ClientException(BaseErrorCode.MANAGER_NULL_ERROR);
        }

        ClerkDO clerkDO = BeanUtil.toBean(requestParam, ClerkDO.class);
        String username = userService.createRandomUsername();
        String password = userService.createRandomPassword();

        clerkDO.setUsername(username);
        clerkDO.setPassword(password);

        int result = baseMapper.insert(clerkDO);

        if (result < 1) {
            throw new ClientException(BaseErrorCode.CLERK_SAVE_ERROR);
        }

        return ClerkSaveRespDTO
                .builder()
                .username(username)
                .password(password)
                .build();
    }

    @Override
    public void deleteClerkById(Long id) {
        ClerkDO clerkDO = baseMapper.selectById(id);

        if (clerkDO == null) {
            throw new ClientException(BaseErrorCode.CLERK_NULL_ERROR);
        }

        isAuthorized(clerkDO.getManagerId());

        int result = baseMapper.deleteById(id);

        if (result < 1) {
            throw new ClientException(BaseErrorCode.CLERK_DELETE_ERROR);
        }
    }

    @Override
    public void updateClerk(ClerkUpdateReqDTO requestParam) {
        isAuthorized(requestParam.getManagerId());

        if (managerMapper.selectById(requestParam.getManagerId()) == null) {
            throw new ClientException(BaseErrorCode.MANAGER_NULL_ERROR);
        }

        int result = baseMapper.updateById(BeanUtil.toBean(requestParam, ClerkDO.class));

        if (result < 1) {
            throw new ClientException(BaseErrorCode.CLERK_UPDATE_ERROR);
        }
    }

    @Override
    public ClerkPageRespDTO pageClerk(Integer pn, Integer ps, Long managerId, String realName) {
        isAuthorized(managerId);

        if (managerId == null) {
            UserInfoDTO userInfoDTO = UserContext.get();

            if (Objects.equals(userInfoDTO.getIdentity(), UserIdentity.manager)) {
                managerId = userInfoDTO.getId();
            }
        }

        Page<ClerkDO> page = new Page<>(pn, ps);
        LambdaQueryWrapper<ClerkDO> lambdaQueryWrapper = Wrappers.lambdaQuery(ClerkDO.class)
                .eq(Objects.nonNull(managerId), ClerkDO::getManagerId, managerId)
                .like(Objects.nonNull(realName), ClerkDO::getRealName, realName)
                .eq(ClerkDO::getDelFlag, DelFlag.present);
        Page<ClerkDO> clerkDOPage = baseMapper.selectPage(page, lambdaQueryWrapper);

        return ClerkPageRespDTO
                .builder()
                .total(clerkDOPage.getTotal())
                .items(clerkDOPage.getRecords())
                .build();
    }

    @Override
    public ListRespDTO<ClerkRealNameRespDTO> listClerkRealName(Long managerId) {
        isAuthorized(managerId);

        if (managerId == null) {
            UserInfoDTO userInfoDTO = UserContext.get();

            if (Objects.equals(userInfoDTO.getIdentity(), UserIdentity.manager)) {
                managerId = userInfoDTO.getId();
            }
        }

        LambdaQueryWrapper<ClerkDO> lambdaQueryWrapper = Wrappers.lambdaQuery(ClerkDO.class)
                .eq(Objects.nonNull(managerId), ClerkDO::getManagerId, managerId)
                .eq(ClerkDO::getDelFlag, DelFlag.present);
        List<ClerkDO> clerkDOList = baseMapper.selectList(lambdaQueryWrapper);

        return ListRespDTO
                .<ClerkRealNameRespDTO>builder()
                .total((long) clerkDOList.size())
                .items(clerkDOList
                        .stream()
                        .map(each -> BeanUtil.toBean(each, ClerkRealNameRespDTO.class))
                        .toList())
                .build();
    }

    /**
     * 判断同级调用是否有权限
     *
     * @param managerId 店长 id
     */
    private void isAuthorized(Long managerId) {
        UserInfoDTO userInfoDTO = UserContext.get();

        // 如果店长 id 不为空，且是店长级别，且店长 id 与当前登录者不同，报错无权限
        if (managerId != null
                && Objects.equals(userInfoDTO.getIdentity(), UserIdentity.manager)
                && !Objects.equals(userInfoDTO.getId(), managerId))
        {
            throw new ClientException(BaseErrorCode.CLIENT_UNAUTHORIZED_ERROR);
        }
    }
}
